package server.doc.xml;

import java.util.*;
import org.dom4j.*;

import server.models.*;
import common.models.MvcModel;
import common.types.GenderType;

public class XMLUserProfile extends XMLDoc {
	
	private static XMLUserProfile xmlProfilePtr = new XMLUserProfile();
	
	public XMLUserProfile() {
		super("data/profiles.xml");
		if (xmlProfilePtr == null)
			xmlProfilePtr = this;
	}
	
	public static XMLUserProfile getInstance() { return xmlProfilePtr; }
	
	synchronized private UserProfile getUser(Element node) {
		if (node == null)
			throw new Error("Null node");
		else {
			Attribute attr = node.attribute("userID");
			int uid = Integer.parseInt(attr.getValue());
			
			String password = node.element("password").getText();
			
			String name = node.element("name").getText();
			
			String genderStr = node.element("gender").getText();
			GenderType gender;
			if (genderStr.equals("male")) gender = GenderType.male;
			else if (genderStr.equals("female")) gender = GenderType.female;
			else gender = GenderType.unknown;
			
			int age = Integer.parseInt(node.element("age").getText());
			
			List list = node.selectNodes("friend");
			ArrayList<Integer> friends = new ArrayList<Integer>();
			for (int i = 0; i < list.size(); ++i) {
				if (list.get(i) instanceof Element) {
					String strUID = ((Element) list.get(i)).attributeValue("userID");
					friends.add(Integer.parseInt(strUID));
				}
			}
			
			return new UserProfile(uid, password, name, gender, age, friends);
		}
	}
	
	synchronized public UserProfile getUser(int uid) {
		Element root = getXML().getRootElement();
		Node node = root.selectSingleNode("/users/user[@userID='" + Integer.toString(uid) + "']");
		if (node instanceof Element)
			return getUser((Element)node);
		else
			throw new Error("User #" + Integer.toString(uid) + " doesn't exist");
	}
	
	synchronized public ArrayList<UserProfile> getUsers() {
		ArrayList<UserProfile> users = new ArrayList<UserProfile>();
		Document xml = getXML();
		Element root = xml.getRootElement();
		List list = root.selectNodes("/users/user");
		for (int i = 0; i < list.size(); ++i) {
			if (list.get(i) instanceof Element) {
				Element node = (Element) list.get(i);
				users.add(getUser(node));
			} else
				throw new Error("type mismatch");
		}
		return users;
	}
	
	synchronized public boolean userExists(int uid) {
		Node node = getXML().getRootElement().selectSingleNode("/users/user[@userID='" + Integer.toString(uid) + "']");
		return node instanceof Element;
	}
	
	synchronized public int nowUserID() {
		Document xml = getXML();
		Node node = xml.getRootElement().selectSingleNode("/users/IDcount");
		if (node instanceof Element) {
			Element elem = (Element) node;
			int uid = Integer.parseInt(elem.getText());
			return uid - 1;
		} else
			throw new Error("node ``IDcount'' not found, xml file modified by hand?");		
	}
	
	synchronized public int newUserID() {
		Document xml = getXML();
		Node node = xml.getRootElement().selectSingleNode("/users/IDcount");
		if (node instanceof Element) {
			Element elem = (Element) node;
			int uid = Integer.parseInt(elem.getText());
			elem.setText(Integer.toString(uid + 1));
			writeFile(xml);
			return uid;
		} else
			throw new Error("node ``IDcount'' not found, xml file modified by hand?");
	}
	
	synchronized public void deleteUser(int uid) {
		Document xml = getXML();
		Element root = xml.getRootElement();
		Node node = root.selectSingleNode("/users/user[@userID='" + Integer.toString(uid) + "']");
		if (node instanceof Element) {
			Element elem = (Element) node;
			root.remove(elem);
			writeFile(xml);
		} else
			throw new Error("user doesn't exist");
	}
	
	synchronized public boolean friendExists(int uid, int fuid) {
		Document xml = getXML();
		Element root = xml.getRootElement();
		Node node = root.selectSingleNode("/users/user[@userID='" + Integer.toString(uid) + "']");
		if (node instanceof Element) {
			Element elem = (Element) node;
			node = elem.selectSingleNode("friend[@userID='" + Integer.toString(fuid) + "']");
			return node instanceof Element;
		} else
			throw new Error("user doesn't exist");
	}
	
	synchronized public void addFriend(int uid, int fuid) {
		Document xml = getXML();
		Element root = xml.getRootElement();
		Node node = root.selectSingleNode("/users/user[@userID='" + Integer.toString(uid) + "']");
		if (node instanceof Element) {
			Element elem = (Element) node;
			elem.addElement("friend").addAttribute("userID", Integer.toString(fuid));
			writeFile(xml);
		} else
			throw new Error("user doesn't exist");
	}
	
	synchronized public void deleteFriend(int uid, int fuid) {
		Document xml = getXML();
		Element root = xml.getRootElement();
		Node node = root.selectSingleNode("/users/user[@userID='" + Integer.toString(uid) + "']");
		if (node instanceof Element) {
			Element elem = (Element) node;
			node = elem.selectSingleNode("friend[@userID='" + Integer.toString(fuid) + "']");
			if (node instanceof Element) {
				Element e = (Element) node;
				elem.remove(e);
			} else
				throw new Error("doesn't have such friend");
		} else
			throw new Error("user doesn't exist");
	}
	
	synchronized public void addEntry(MvcModel entry) {
		if (entry instanceof UserProfile) {
			UserProfile profile = (UserProfile) entry;
			Document xml = getXML();
			Element root = xml.getRootElement();
			Element user = root.addElement("user");
			user.addAttribute("userID", Integer.toString(profile.getUserID()));
			(user.addElement("password")).setText(profile.getPassword());
			(user.addElement("name")).setText(profile.getName());
			(user.addElement("gender")).setText(profile.getGender().toString());
			(user.addElement("age")).setText(Integer.toString(profile.getAge()));
			for (Integer fuid : profile.getFriends())
				user.addElement("friend").addAttribute("userID", fuid.toString());
			writeFile(xml);
		} else
			throw new Error("Entry is not a profile of user");
	}

	synchronized public void deleteEntry(MvcModel entry) {
		if (entry instanceof UserProfile) {
			UserProfile profile = (UserProfile) entry;
			Document xml = getXML();
			Element root = xml.getRootElement();
			Node node = root.selectSingleNode("/users/user[@userID='" + Integer.toString(profile.getUserID()) + "']");
			if (node instanceof Element) {
				Element elem = (Element) node;
				root.remove(elem);
				writeFile(xml);
			} else
				throw new Error("User #" + Integer.toString(profile.getUserID()) + " doesn't exist");
		} else
			throw new Error("Entry is not a profile of user");
	}

	synchronized public void updateEntry(MvcModel entry) {
		deleteEntry(entry);
		addEntry(entry);
	}

	@Override
	synchronized public Document initXML() {
		// TODO Auto-generated method stub
		Document xml = DocumentHelper.createDocument();
		(xml.addElement("users").addElement("IDcount")).setText("0");
		
/*		Element users = xml.addElement("users");*/
		
/*		Element admin = users.addElement("user");
		admin.addAttribute("userID", "0");
		
		Element nameElement = admin.addElement("name");
		nameElement.setText("test");*/
		
/*		Element adminElement = admin.addElement("isAdmin");
		adminElement.setText("true");*/
		
/*		Element pwdElement = admin.addElement("password");
		pwdElement.setText("123456");
		
		admin.addElement("gender", "");
		admin.addElement("birthday", "");
		admin.addElement("friends", "");*/
		return xml;
	}
	
	/*public static void main(String[] args) {
		XMLUserProfile pfile = new XMLUserProfile();
		pfile.getXML();
	}*/
}
